/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls;

import com.fasterxml.jackson.databind.JsonSerializer;
import com.inspur.edp.cef.entity.condition.SortCondition;
import com.inspur.edp.cef.spi.entity.info.CefEntityTypeInfo;
import com.inspur.edp.cef.spi.entity.info.EnumValueInfo;
import com.inspur.edp.cef.spi.entity.info.UniqueConstraintInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.EnumPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ObjectType;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.SimpleEnumUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.EntityResInfo;
import com.inspur.edp.cef.spi.jsonser.entity.AbstractEntitySerializerItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class CefEntityResInfoImpl extends EntityResInfo {

    private CefEntityTypeInfo entityTypeInfo;
    private Map<String, EntityResInfo> childEntityResInfos;
    private CefModelResInfoImpl modelResInfo;
    private String entityId;
    private List<SortCondition> sorts;
    private ArrayList<String> propertyNames;
    private  boolean isInitingAssMapping =false;

    public String getConfigId() {
        return "";
    }

    public final CefModelResInfoImpl getModelResInfo()
    {return modelResInfo;}

    public JsonSerializer getEntitySerConvertor() {
        return null;
    }

    public CefEntityResInfoImpl(String entityCode, String displayValueKey,
        CefModelResInfoImpl modelResInfo, String entityId) {
        this.entityId = entityId;
        entityTypeInfo = new CefEntityTypeInfo(entityCode, displayValueKey);
        this.modelResInfo = modelResInfo;
        initColumns();
        initUQConstraintInfos();
        initChildInfos(modelResInfo);
    }

    public String getVersionControlPropertyName()
    {return "";}

    protected final String getDisplayPrefix() {

        return entityTypeInfo.getDisplayValueKey()
            .substring(0, entityTypeInfo.getDisplayValueKey().lastIndexOf("."));
    }

    public String getPrimaryKey() {
        return "ID";
    }

    public String getParentProprety() {
        return "ParentID";
    }

    /**
     * 运行时获取propertyNames
     *
     * @return propertyName集合
     */
    public ArrayList<String> getPropertyNames() {
        ArrayList<String> propertyNamesTemp;
        if (propertyNames == null) {
            propertyNamesTemp = new ArrayList<>();
                propertyNames = new ArrayList<>();
            propertyNamesTemp.addAll(entityTypeInfo.getPropertyInfos().keySet());
            // todo 加入大写
            if (childEntityResInfos != null) {
                childEntityResInfos.keySet().forEach(str -> {
                    String child = str + "s";
                    propertyNamesTemp.add(child);
                    String upperChild = toUpperCaseFirstOne(child);
                    // 子对象首字母时小写时要加入大写
                    if (!child.equals(upperChild)) {
                        propertyNamesTemp.add(upperChild);
                    }
                });
            }
            propertyNamesTemp.removeAll(Collections.singleton(null));
            propertyNames = new ArrayList<>(propertyNamesTemp.size());
            propertyNames.addAll(propertyNamesTemp);
        }
        return propertyNames;
    }

    private String toUpperCaseFirstOne(String s) {
        if (Character.isUpperCase(s.charAt(0))) {
            return s;
        } else {
            return Character.toUpperCase(s.charAt(0)) + s.substring(1);
        }
    }

    protected void initColumns() {
    }

    protected void initChildInfos(CefModelResInfoImpl modelResInfo) {
    }

    protected void initUQConstraintInfos() {
    }


    protected final void addPropertyInfo(DataTypePropertyInfo propertyInfo) {
        entityTypeInfo.getPropertyInfos().put(propertyInfo.getPropertyName(), propertyInfo);
    }

    protected final void addUQConstraintInfo(String uniqueConCode, UniqueConstraintInfo uqInfo) {
        entityTypeInfo.addUnitConstraintInfo(uniqueConCode, uqInfo);
    }

    protected final void addUQConstraintInfo(String uniqueConCode, ArrayList<String> elements) {
        addUQConstraintInfo(uniqueConCode, getDisplayPrefix() + "." + uniqueConCode + ".TipInfo",
            elements);
    }

    protected final void addUQConstraintInfo(String uniqueConCode, String elements)
    { addUQConstraintInfo(uniqueConCode, getDisplayPrefix() + "." + uniqueConCode + ".TipInfo",
        elements);}

    protected final void addUQConstraintInfo(String uniqueConCode,String displayValueKey, String elements)
    {
        ArrayList<String> eleList =new ArrayList<>();
        if(elements!=null&&!elements.equals(""))
        {
            String[] array =  elements.split(",");
            for (String item:array)
            {
                eleList.add(item);
            }
        }
        addUQConstraintInfo(uniqueConCode,displayValueKey,eleList);

    }

    protected final void addUQConstraintInfo(String uniqueConCode, String displayValueKey,
        ArrayList<String> elements) {
        UniqueConstraintInfo uq_testuqConstraintInfo = new UniqueConstraintInfo();
        uq_testuqConstraintInfo.setDisplayValueKey(displayValueKey);
        uq_testuqConstraintInfo.setFields((ArrayList<String>) elements);
        uq_testuqConstraintInfo.setNodeCode(getEntityCode());
        addUQConstraintInfo(uniqueConCode, uq_testuqConstraintInfo);

    }

    @Override
    public String getEntityCode() {
        return entityTypeInfo.getEntityCode();
    }

    @Override
    public final String getUniqueConstraintMessage(String uniqueConCode) {
        return modelResInfo.getResourceItemValue(
            entityTypeInfo.getUniqueConstraintInfos().get(uniqueConCode).getDisplayValueKey());
    }


    @Override
    public final String getDisplayName() {
        return modelResInfo.getResourceItemValue(entityTypeInfo.getDisplayValueKey());
    }

    public final String getI18nPrefix() {
        return entityTypeInfo.getDisplayValueKey()
            .substring(0, entityTypeInfo.getDisplayValueKey().length() - 6);
    }

    @Override
    public String getPropertyDispalyName(String labelId) {
        String resourceKey = entityTypeInfo.getPropertyInfos().get(labelId).getDisplayValueKey();
        return modelResInfo.getResourceItemValue(resourceKey);
    }

    @Override
    public String getEnumPropertyDispalyValue(String labelId, String enumKey) {
        DataTypePropertyInfo info = entityTypeInfo.getPropertyInfos().get(labelId);
        if (info != null) {
            if (info.getObjectType() == ObjectType.Enum) {
                return modelResInfo.getResourceItemValue(
                    ((EnumPropertyInfo) info.getObjectInfo()).getEnumValueInfo(enumKey)
                        .getDisplayValueKey());
            } else if (info.getObjectInfo() instanceof SimpleEnumUdtPropertyInfo) {
                return modelResInfo.getResourceItemValue(
                    (((SimpleEnumUdtPropertyInfo) info.getObjectInfo()).getEnumInfo())
                        .getEnumValueInfo(enumKey)
                        .getDisplayValueKey());
            }
        }
        throw new RuntimeException("当前属性" + labelId + "不是枚举类型，无法获取枚举值");
    }

    @Override
    public String getAssoRefEnumPropertyDisplayValue(String labelId, String refEleCode,
        String enumKey) {
        DataTypePropertyInfo dataTypePropertyInfo = entityTypeInfo.getPropertyInfo(labelId);
        AssocationPropertyInfo associationPropertyInfo = (AssocationPropertyInfo) dataTypePropertyInfo
            .getObjectInfo();
        DataTypePropertyInfo info = associationPropertyInfo.getAssociationInfo().getRefPropInfos()
            .get(refEleCode);

        if (info.getObjectType() == ObjectType.Enum) {
            return modelResInfo.getResourceItemValue(
                ((EnumPropertyInfo) info.getObjectInfo()).getEnumValueInfo(enumKey)
                    .getDisplayValueKey());
        } else if (info.getObjectInfo() instanceof SimpleEnumUdtPropertyInfo) {
            return modelResInfo.getResourceItemValue(
                (((SimpleEnumUdtPropertyInfo) info.getObjectInfo()).getEnumInfo())
                    .getEnumValueInfo(enumKey)
                    .getDisplayValueKey());
        }
        throw new RuntimeException("当前属性" + labelId + "不是枚举类型，无法获取枚举值");
    }

    @Override
    public EnumValueInfo getPropEnumInfo(String labelId, String enumKey) {
        DataTypePropertyInfo info = entityTypeInfo.getPropertyInfos().get(labelId);
        if (info.getObjectType() == ObjectType.Enum) {
            return ((EnumPropertyInfo) info.getObjectInfo()).getEnumValueInfo(enumKey);
        }
        throw new RuntimeException("当前属性" + labelId + "不是枚举类型，无法获取枚举值");

    }

    @Override
    public List<EnumValueInfo> getPropEnumInfos(String labelId) {
        DataTypePropertyInfo info = entityTypeInfo.getPropertyInfos().get(labelId);
        if (info.getObjectType() == ObjectType.Enum) {
            return ((EnumPropertyInfo) info.getObjectInfo()).getEnumValueInfos();
        }
        throw new RuntimeException("当前属性" + labelId + "不是枚举类型，无法获取枚举值");
    }

    @Override
    public String getAssoRefPropertyDisplay(String labelId, String refEleCode) {
        DataTypePropertyInfo dataTypePropertyInfo = entityTypeInfo.getPropertyInfo(labelId);
        AssocationPropertyInfo associationPropertyInfo = (AssocationPropertyInfo) dataTypePropertyInfo
            .getObjectInfo();
        return this.modelResInfo.getResourceItemValue(
            associationPropertyInfo.getAssociationInfo().getRefPropInfos().get(refEleCode)
                .getDisplayValueKey());
    }

    protected final void addChildEntityResInfo(EntityResInfo info) {
        if (childEntityResInfos == null)
            childEntityResInfos = new HashMap<>();
        childEntityResInfos.put(info.getEntityCode(), info);
    }

    @Override
    public final EntityResInfo getChildEntityResInfo(String entityCode) {
        EntityResInfo rez = childEntityResInfos != null ?  childEntityResInfos.get(entityCode) : null;
        if(rez != null)
            return rez;
        throw new RuntimeException(
            String.format("编号为[%s]的节点上不存在编号为[%s]的子节点.", getEntityCode(), entityCode));
    }


    public Map<String, EntityResInfo> getChildEntityResInfos() {
        return childEntityResInfos;
    }

    public boolean isRoot() {
        // 主表生产代码，切覆盖为true，子表不生成
        return false;
    }

    public List<AbstractEntitySerializerItem> getChangeDeserialzers() {
        throw new UnsupportedOperationException();
    }

    public CefEntityTypeInfo getEntityTypeInfo() {
        return entityTypeInfo;
    }

    public String getEntityId() {
        return entityId;
    }

    public List<SortCondition> getSorts() {
        return this.sorts;
    }

    public void setSorts(List<SortCondition> sorts) {
        this.sorts = sorts;
    }




    private Object sqlSnippetCache;

    public Object getSqlSnippetCache() {
        return sqlSnippetCache;
    }

    public void setSqlSnippetCache(Object sqlSnippetCache) {
        this.sqlSnippetCache = sqlSnippetCache;
    }

    protected final Class creteClass(String className)
    {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    protected final Class createClass(String className)
    {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public boolean isInitingAssMapping() {
        return isInitingAssMapping;
    }

    public void setInitingAssMapping(boolean initingAssMapping) {
        isInitingAssMapping = initingAssMapping;
    }
}
